
package foxesAndRabbits;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

/**
 * A graphical view of the simulation grid.
 * The view displays a colored rectangle for each location 
 * representing its contents. It uses a default background color.
 * Colors for each type of species can be defined using the
 * setColor method.
 * 
 * @author David J. Barnes and Michael Kolling
 * @editor (Stephan Veenstra, Marc Bruins, Michel Jansma)
 * @version 2012.11.08
 */
public class SimulatorView extends JFrame {
	
    //Instantie variabelen van het type Color
    private static final Color EMPTY_COLOR   = Color.white,
    						   UNKNOWN_COLOR = Color.gray;
    //Instantie variabelen van het type String
    private final String STEP_PREFIX       = "Step: ",
    			  		 POPULATION_PREFIX = "Population: ";
    //Instantie variabelen van het type JLabel
    private JLabel stepLabel, population;
    //Instantie variabelen van het type JButton
    private JButton smallButton, largeButton, resetButton, musicStopButton;
    //Instantie variabelen van het type FieldView
    private FieldView fieldView;
    //Instantie variabelen van het type Simulator
    private Simulator simulator;
    // A map for storing colors for participants in the simulation
    private Map<Class, Color> colors;
    // A statistics object computing and storing simulation information
    private FieldStats stats;

    /**
     * Create a view of the given width and height.
     * @param height The simulation's height.
     * @param width  The simulation's width.
     */
    public SimulatorView(int height, int width) {
    	
    	this.stepLabel   = new JLabel(STEP_PREFIX, JLabel.CENTER);
    	this.population  = new JLabel(POPULATION_PREFIX, JLabel.CENTER);
    	this.smallButton = new JButton("Step 1");
    	this.largeButton = new JButton("Step 100");
    	this.resetButton = new JButton("Reset");
    	this.musicStopButton = new JButton("Stop music");
    	this.fieldView   = new FieldView(height, width);
    	this.stats       = new FieldStats();
    	this.colors      = new LinkedHashMap<Class, Color>();

        //Initialiseer fram attributen
        this.setAttributes();
        //Render Simulator menu balk
        this.setSimulatorMenuBar();
        //Set layout content pane
        this.getContentPane().setLayout(new BorderLayout());
        //
        this.getContentPane().add(this.stepLabel, BorderLayout.NORTH);
        //Render step panel 
        this.setStepPanel();
        //Render content panel
        this.setContentPanel();
        //
        this.getContentPane().add(this.population, BorderLayout.SOUTH);
        //Render simulatie
        this.renderSimulation();
        
    }
    
    /**
     * @method renderSimulation
     * @params null
     * @info   Render simulatie 
     * @return null
     */
    private void renderSimulation() {
    	this.pack();
    	this.setVisible(true);
    }
    
    private void setAttributes() {
    	//Set configuratie attributen
        this.setTitle("Vossen & Konijnen");
        this.setLocation(100, 50);
    }
    
    /***************************************************************
     * V&K SIMULATOR DATA START
     **************************************************************/
    
    /**
     * @method setSimulator
     * @params <Simulator> simulator
     * @info   Maak simulator instantie bereikbaar voor simulator view
     * @return null
     */
    public void setSimulator(Simulator simulator) {
    	this.simulator = simulator;
    }
    
    /**
     * @method getSimulator
     * @params null
     * @info   Retourneer instantie variabele simulator
     * @return <Simulator> simulator
     */
    public Simulator getSimulator() {
    	return this.simulator;
    }
    
    /***************************************************************
     * V&K SIMULATOR DATA END
     **************************************************************/
    
    /***************************************************************
     * V&K MENU DATA START
     **************************************************************/
    
    /**
     * @method setSimulatorMenuBar
     * @params null
     * @info   Render simulator menu balk 
     * @return null
     */
    private void setSimulatorMenuBar() {
    	//Maak menu balk aan
        JMenuBar bar = this.addMenuBar();
        //Maak menus aan
        JMenu menu1  = this.addMenu(bar, "Menu 1");
        JMenu menu2  = this.addMenu(bar, "Menu 2");
        JMenu help   = this.addMenu(bar, "Help");
        //Maak menu items aan
        HashMap<String, JMenuItem> items = new HashMap<String, JMenuItem>();
        items.put("testFrame", new JMenuItem("Menu1, item1"));
        //Voeg menu items toe en leeg hashmap
        this.addMenuItems(menu1, items);
        items.clear();
        items.put("testFrame", new JMenuItem("Menu2, item1"));
        //Voeg menu items toe en leeg hashmap
        this.addMenuItems(menu2, items);
        items.clear();
        items.put("helpFrame", new JMenuItem("Menu3, item1"));
        //Voeg menu items toe en leeg hashmap
        this.addMenuItems(help, items);
    }
    
    /**
     * @method addMenuBar
     * @params null
     * @info   Voeg een menubalk toe aan de simulator
     * @return <JMenuBar> bar
     */
    private JMenuBar addMenuBar() {
    	JMenuBar bar = new JMenuBar();
    	this.setJMenuBar(bar);
    	return bar;
    }
    
    /**
     * @method addMenuBar
     * @params <JMenuBar> bar, <String> title
     * @info   Voeg een menu toe aan een menubalk
     * @return <JMenu> menu
     */
    private JMenu addMenu(JMenuBar bar, String title) {
    	JMenu menu = new JMenu(title);
    	bar.add(menu);
    	return menu;
    }
    
    /**
     * @method addMenuItems
     * @params <JMenu> menu, <HashMap<String,JMenuItem> items
     * @info   Voeg menu items toe aan menu 
     * @return <JMenu> menu
     */
    private void addMenuItems(JMenu menu, HashMap<String, JMenuItem> items) {
		//Loop door menu items
		int index = 0;
		//Items iterator
		Iterator it = items.keySet().iterator();
		while(it.hasNext()) {
			String key = it.next().toString();
			JMenuItem item  = items.get(key);
			item.addActionListener(new EventHandler(this, key));
			menu.add(item);
		}
    }
    
    /***************************************************************
     * V&K MENU DATA END
     **************************************************************/
    
    private EventHandler setEventHandler(String handler, HashMap<String, JComponent> params) {
    	return new EventHandler(this, handler, params);
    }
    
    /***************************************************************
     * V&K STEP PANEL DATA START
     **************************************************************/
    
    public void setStepPanel() {
    	//Small button
    	HashMap<String,JComponent> params = new HashMap<String,JComponent>();
    	params.put("step", this.smallButton);
    	//this.smallButton.setLabel("1");
    	this.smallButton.addActionListener(new EventHandler(this, "handleStepRequest", params));
    	//Large button
    	params.clear();
    	params.put("step", this.largeButton);
    	this.largeButton.addActionListener(this.setEventHandler("handleStepRequest", params));
    	//Reset button
    	params.clear();
    	params.put("step", this.resetButton);
    	this.resetButton.addActionListener(this.setEventHandler("handleStepRequest", params));
    	//Reset button
    	params.clear();
    	params.put("stopMusicButton", this.musicStopButton);
    	this.musicStopButton.addActionListener(this.setEventHandler("stopStartMusic", params));

    	//Step panel
        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());
        //Inner layout
        JPanel inner = new JPanel();
        inner.setLayout(new GridLayout(0,1));
        //Voeg items toe aan inner layout
        inner.add(this.smallButton);
        inner.add(this.largeButton);
        inner.add(this.resetButton);
        inner.add(this.musicStopButton);
        //Voeg inner layout toe aan panel
        panel.add(inner);
        //Voeg panel toe aan content pane
        this.getContentPane().add(panel, BorderLayout.WEST);
    }
    
    public void setContentPanel() {
        //Voeg panel toe aan content pane
        this.getContentPane().add(this.fieldView, BorderLayout.CENTER);
    }
    
    /***************************************************************
     * V&K STEP PANEL DATA END
     **************************************************************/
    
    
    /**
     * Define a color to be used for a given class of animal.
     * @param animalClass The animal's Class object.
     * @param color The color to be used for the given class.
     */
    public void setColor(Class animalClass, Color color)
    {
        colors.put(animalClass, color);
    }

    /**
     * @return The color to be used for a given class of animal.
     */
    private Color getColor(Class animalClass)
    {
        Color col = colors.get(animalClass);
        if(col == null) {
            // no color defined for this class
            return UNKNOWN_COLOR;
        }
        else {
            return col;
        }
    }

    /**
     * Show the current status of the field.
     * @param step Which iteration step it is.
     * @param field The field whose status is to be displayed.
     */
    public void showStatus(int step, Field field)
    {
        if(!isVisible()) {
            setVisible(true);
        }
            
        stepLabel.setText(STEP_PREFIX + step);
        stats.reset();
        
        fieldView.preparePaint();

        for(int row = 0; row < field.getDepth(); row++) {
            for(int col = 0; col < field.getWidth(); col++) {
                Object animal = field.getObjectAt(row, col);
                if(animal != null) {
                    stats.incrementCount(animal.getClass());
                    fieldView.drawMark(col, row, getColor(animal.getClass()));
                }
                else {
                    fieldView.drawMark(col, row, EMPTY_COLOR);
                }
            }
        }
        stats.countFinished();

        population.setText(POPULATION_PREFIX + stats.getPopulationDetails(field));
        fieldView.repaint();
    }

    /**
     * Determine whether the simulation should continue to run.
     * @return true If there is more than one species alive.
     */
    public boolean isViable(Field field)
    {
        return stats.isViable(field);
    }
    
    /**
     * Provide a graphical view of a rectangular field. This is 
     * a nested class (a class defined inside a class) which
     * defines a custom component for the user interface. This
     * component displays the field.
     * This is rather advanced GUI stuff - you can ignore this 
     * for your project if you like.
     */
    private class FieldView extends JPanel
    {
        private final int GRID_VIEW_SCALING_FACTOR = 6;

        private int gridWidth, gridHeight;
        private int xScale, yScale;
        Dimension size;
        private Graphics g;
        private Image fieldImage;

        /**
         * Create a new FieldView component.
         */
        public FieldView(int height, int width)
        {
            gridHeight = height;
            gridWidth = width;
            size = new Dimension(0, 0);
        }

        /**
         * Tell the GUI manager how big we would like to be.
         */
        public Dimension getPreferredSize()
        {
            return new Dimension(gridWidth * GRID_VIEW_SCALING_FACTOR,
                                 gridHeight * GRID_VIEW_SCALING_FACTOR);
        }

        /**
         * Prepare for a new round of painting. Since the component
         * may be resized, compute the scaling factor again.
         */
        public void preparePaint()
        {
            if(! size.equals(getSize())) {  // if the size has changed...
                size = getSize();
                fieldImage = fieldView.createImage(size.width, size.height);
                g = fieldImage.getGraphics();

                xScale = size.width / gridWidth;
                if(xScale < 1) {
                    xScale = GRID_VIEW_SCALING_FACTOR;
                }
                yScale = size.height / gridHeight;
                if(yScale < 1) {
                    yScale = GRID_VIEW_SCALING_FACTOR;
                }
            }
        }
        
        /**
         * Paint on grid location on this field in a given color.
         */
        public void drawMark(int x, int y, Color color)
        {
            g.setColor(color);
            g.fillRect(x * xScale, y * yScale, xScale-1, yScale-1);
        }

        /**
         * The field view component needs to be redisplayed. Copy the
         * internal image to screen.
         */
        public void paintComponent(Graphics g)
        {
            if(fieldImage != null) {
                Dimension currentSize = getSize();
                if(size.equals(currentSize)) {
                    g.drawImage(fieldImage, 0, 0, null);
                }
                else {
                    // Rescale the previous image.
                    g.drawImage(fieldImage, 0, 0, currentSize.width, currentSize.height, null);
                }
            }
        }
    }
}

